#include "cp.h"
#include <iostream>

using namespace bnf;

std::string s = "-(1+2)*-3";

typedef Interface<double> Calc;

Calc DoBracket(std::vector<Calc> &res)
{
    return *res[0].text == '(' ? res[1] : res[0];
}

Calc DoNumber(std::vector<Calc> &res)
{
    char *lst;
    double value = strtod(res[0].text, &lst);
    Calc ret(value, res);
    return ret;
}

Calc DoUnary(std::vector<Calc> &res)
{
    if (*res[0].text == '-')
        return Calc(-res[1].data, res);
    else if (*res[0].text == '+')
        return Calc(res[1].data, res);
    else
        return Calc(res[0].data, res);
}

Calc DoBinary(std::vector<Calc> &res)
{
    double value = res[0].data;
    for (unsigned int i = 1; i < res.size(); i += 2)
    {
        switch (*res[i].text)
        {
        case '+':
            value += res[i + 1].data;
            break;
        case '-':
            value -= res[i + 1].data;
            break;
        case '*':
            value *= res[i + 1].data;
            break;
        case '/':
            value /= res[i + 1].data;
            break;
        case '%':
            value = (int)value % (int)res[i + 1].data;
            break;
        }
    }
    return Calc(value, res);
}

int main()
{
    Token digit1_9('1', '9');
    Token DIGIT("0123456789");
    Lexem int_ = "0" | digit1_9 + *DIGIT;
    Rule number = !Token("-") + int_;
    Bind(number, DoNumber);
    Rule Expression;
    Bind(Expression, Calc::ByPass);
    Rule PrimaryExpression = "(" + Expression + ")" | number;
    Bind(PrimaryExpression, DoBracket);
    Rule UnaryExpression = !Token("+-") + PrimaryExpression;
    Bind(UnaryExpression, DoUnary);
    Rule MulExpression = UnaryExpression + *("*%/" + UnaryExpression);
    Bind(MulExpression, DoBinary);
    Rule AddExpression = MulExpression + *("+-" + MulExpression);
    Bind(AddExpression, DoBinary);
    Expression = AddExpression;

    const char *tail = 0;
    Calc result;
    int tst = Analyze(Expression, s.c_str(), &tail, result);
    if (tst > 0)
    {
        std::cout << result.data << std::endl;
    }
    return 0;
}